package DataModel.CommonLibrary;

import java.util.Hashtable;
import java.util.LinkedList;

import DataModel.CommonLibrary.CommonDefs.Layer;
import DataModel.LayoutManager.CEdge;
import DataModel.LayoutManager.CRectangle;
import ScanLineAlghorithms.RectanglesIntersection;
import ScanLineAlghorithms.RectanglesUnion.RectanglesUnion;
import WhiteSpaceReport.WhiteSpaceByRect;

/**
 * Geometric operations on rectangles (static functions)
 * @author evgeni
 *
 */
public class CGeometricOperations 
{
	/**
	 * Calculation of empty spaces in given area
	 * @param area area where to find empty spaces
	 * @param recsInArea rectangles residing in this area
	 * @param dir -direction od the sweepin of the plain
	 * @return - rectangles representing empty areas
	 */
	public static  LinkedList<CRectangle>  findWhiteSpaceByRect (CRectangle area,LinkedList<CRectangle> recsInArea, LinkedList<CRectangle> freeArea , char dir) 
	{
		return WhiteSpaceByRect.findWhiteSpaceByRect(area, recsInArea ,dir);
	}
	/**
	 * Finding minimal empty space that can include given rectangle
	 * @param inputRec rectangle we want to place
	 * @param area area in which we want to place
	 * @param recsInArea other rectangles residing in the area
	 * @return rectangle
	 */
	public static CRectangle findMinEnclosing(CRectangle inputRec, CRectangle area,LinkedList<CRectangle> recsInArea) {
		return WhiteSpaceByRect.findMinEnclosing(inputRec,area,recsInArea);
	}
	
	/**
	 * Rectangles inersection algorithm based on scan line.
	 * @param recsList - linked list of rectangles among which we want to find intersecting pairs
	 *        recsConnected - Hash table that contains intersection result. Key : rectangle Data : list of rectangles intersecting with the key
	 * @param recsConnected 
	 */
	public static void rectanglesIntersection(LinkedList<CRectangle> recsList, Hashtable<Long, LinkedList<CRectangle>> recsConnected) {
		RectanglesIntersection.Activate(recsList, recsConnected);

	}

	
	
	/**
	 * Calculates union of given set of rectangles.
	 * Direction of perimeter is such that when walking from edge start to its end , 
	 * the enclosed union is on the right side
	 * @param recsList input rectangles to unite
	 * @return all edges of the union in order
	 */
	public static LinkedList<CEdge> rectanglesUnion(LinkedList<CRectangle> recsList) {
		return RectanglesUnion.Activate(recsList);
	}	
	/**
	 * Given two horizontal lines, report all rectangles placed between these lines
	 * or intersected with them
	 * @param bottomY - bottom horizontal line
	 * @param topY - upper horizontal line
	 * @param allRecsList - rectangles list participating in the calculation
	 * @return list of rectangles placed between the lines
	 */
	public static LinkedList<CRectangle> RecsInHorisontalArea(long bottomY, long topY, LinkedList<CRectangle> allRecsList)
	{
		LinkedList<CRectangle> insideRecs = new LinkedList<CRectangle>();
		
		for (CRectangle rectangle : allRecsList) {
			if(!(rectangle.getTopEdge().getStartPoint().y <= bottomY || rectangle.getBottomEdge().getStartPoint().y >= topY))
				insideRecs.add(rectangle);
		}
		
		return insideRecs;
	}
	
	
	/**
	 * Given two vertical lines, report all rectangles placed between these lines
	 * or intersected with them
	 * @param leftX - left vertical line
	 * @param rightX - right vertical line
	 * @param allRecsList - rectangles list participating in the calculation
	 * @return list of rectangles placed between the lines
	 */
	public static LinkedList<CRectangle> RecsInVerticalArea(long leftX, long rightX, LinkedList<CRectangle> allRecsList)
	{
		LinkedList<CRectangle> insideRecs = new LinkedList<CRectangle>();
		
		for (CRectangle rectangle : allRecsList) {
			if(!(rectangle.getLeftEdge().getStartPoint().x >= rightX || rectangle.getRightEdge().getStartPoint().x <= leftX))
				insideRecs.add(rectangle);
		}
		
		return insideRecs;
	}
	
	
	/**
	 * Given a list of rectangles, calculate their bounding box
	 * @param recsList - list of rectangles
	 * @return Rectangle of the bounding box
	 */
	public static CRectangle GetBoundingBox(LinkedList<CRectangle> recsList)
	{
		return new CRectangle(
				GetLeftestEdgeRectangle(recsList).getLeftEdge().getStartPoint().x,
				GetBottomestEdgeRectangle(recsList).getBottomEdge().getStartPoint().y,
				GetRightestEdgeRectangle(recsList).getRightEdge().getStartPoint().x,
				GetTopestEdgeRectangle(recsList).getTopEdge().getStartPoint().y,
				Layer.None,
				-1);
	}
	

	/**
	 * Given an area and a rectangles list, find all rectangles occupying that area
	 * @param areaRec - area in the layout
	 * @param recsList - list of rectangles
	 * @return list of rectangles occupying given area
	 */
	public static LinkedList<CRectangle> GetRectanglesInArea(CRectangle areaRec, LinkedList<CRectangle> recsList)
	{
		LinkedList<CRectangle> occupRecs = new LinkedList<CRectangle>();
		
		for (CRectangle rectangle : recsList) 
		{
			if(areaRec.isIntersecting(rectangle))
				occupRecs.add(rectangle);
		}
		
		return occupRecs;
	}
	
	/**
	 * Given a list of rectangles, find the rectangle with the "leftest" left edge
	 * @param recsList - rectangles list
	 * @return Rectangle with the "leftest" left edge 
	 */
	public static CRectangle GetLeftestEdgeRectangle(LinkedList<CRectangle> recsList)
	{
		CRectangle leftestRec = null;
		long leftestVal = Long.MAX_VALUE;
		long currVal;
		
		for (CRectangle rectangle : recsList) 
		{
			currVal = rectangle.getLeftEdge().getStartPoint().x;
			
			if( currVal < leftestVal)
			{
				leftestRec = rectangle;
				leftestVal = currVal;
			}
		}
		
		return leftestRec;
	}
	
	
	/**
	 * Given a list of rectangles, find the rectangle with the "rightest" right edge
	 * @param recsList - rectangles list
	 * @return Rectangle with the "rightest" right edge
	 */
	public static CRectangle GetRightestEdgeRectangle(LinkedList<CRectangle> recsList)
	{
		CRectangle rightestRec = null;
		long rightestVal = 0;
		long currVal;
		
		for (CRectangle rectangle : recsList) 
		{
			currVal = rectangle.getRightEdge().getStartPoint().x;
			
			if( currVal > rightestVal)
			{
				rightestRec = rectangle;
				rightestVal = currVal;
			}
		}
		
		return rightestRec;
	}
	
	/**
	 * Given a list of rectangles, find the rectangle with the "topest" top edge
	 * @param recsList - rectangles list
	 * @return Rectangle with the "topest" top edge
	 */
	public static CRectangle GetTopestEdgeRectangle(LinkedList<CRectangle> recsList)
	{
		CRectangle topestRec = null;
		long topestVal = 0;
		long currVal;
		
		for (CRectangle rectangle : recsList) 
		{
			currVal = rectangle.getTopEdge().getStartPoint().y;
			
			if( currVal > topestVal)
			{
				topestRec = rectangle;
				topestVal = currVal;
			}
		}
		
		return topestRec;
	}
	
	/**
	 * Given a list of rectangles, find the rectangle with the "bottomest" bottom edge
	 * @param recsList - rectangles list
	 * @return Rectangle with the "bottomest" bottom edge
	 */
	public static CRectangle GetBottomestEdgeRectangle(LinkedList<CRectangle> recsList)
	{
		CRectangle bottomRec = null;
		long bottomVal = Long.MAX_VALUE;
		long currVal;
		
		for (CRectangle rectangle : recsList) 
		{
			currVal = rectangle.getBottomEdge().getStartPoint().y;
			
			if( currVal < bottomVal)
			{
				bottomRec = rectangle;
				bottomVal = currVal;
			}
		}
		
		return bottomRec;
	}
	
	
	
	
}

